/**
 * @Title: SysInterceptor.java
 * @Package com.eppear.jpfm.framework.interceptor
 * @Description: 
 * @author JianFeng Zhang(张建锋)
 * @date 2016-12-15 下午10:48:44
 * @version 
 */
package com.eppear.jpfm.framework.interceptor;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.eppear.jpfm.framework.constants.Constants;

/**
 * @ClassName SysInterceptor
 * @Description 继承HandlerInterceptorAdapter类，并根据需求实现其中的preHandle方法（预处理）、
 *              postHandle方法（返回处理），afterCompletion方法（后处理）。
 * @author JianFeng Zhang(张建锋)
 * @date 2016-12-15 下午10:48:44
 *
 */
public class SysInterceptor extends HandlerInterceptorAdapter {

	private static Logger log = LoggerFactory.getLogger(SysInterceptor.class);
	private NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<Long>("StopWatch-StartTime");

	/**
	 * @Description 请求进到业务层控制器前的处理,主要有登录识别,日志记录,性能时间戳记录等.
	 * 
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		log.info("*******************MVC业务处理开始**********************");
		try {
			long beginTime = System.currentTimeMillis();
			startTimeThreadLocal.set(beginTime);
			String requestURL = request.getRequestURI();
			log.info("当前请求的URL：【{}】", requestURL);
			log.info("请求的目标方法:{}", handler);
			Map<String, ?> params = transToMAP(request.getParameterMap());
			if (!params.isEmpty()) {
				log.debug("当前请求参数打印：");
				_print("参数 ", params);
			}

			// 系统开关
			String sysSwitch = "1";// (String)
									// Context.getParamCacheData(Constants.SYS_SWITCH);
			boolean ifWhiteList = whiteListCheck(request);

			// 系统关闭时 ，只有系统管理员能登录
			if (Constants.SYS_SWITCH_OFF.equals(sysSwitch)) {
				if (!ifWhiteList) {
					// TODO 需要后期完善系统开关的处理
				}
			}
			/* 需要登录但没登录的 */
			if (!ifWhiteList && !hasLogin(request)) {
				request.getRequestDispatcher(Constants.LOGIN_JSP_NAME).forward(request, response);
				//Context.clear();
				return false;
			}

			// TODO记录当前请求的菜单项ID,为返回时做数据记录,后期有好办法时,则去掉此处理
			String currentLeafMenuId = request.getParameter(Constants.CURRENT_MENU_LEAF_ID);
			if (currentLeafMenuId != null) {
				if (!"".equals(currentLeafMenuId.trim())) {
					request.getSession().setAttribute(Constants.CURRENT_MENU_LEAF_ID, currentLeafMenuId);
				}
			}
		} catch (Exception e) {
			log.error("MVC业务处理-拦截器异常：", e);
		}
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {

		//log.info("--------- 一个MVC 视图渲染开始  ---------");
		try {
			log.info("执行业务逻辑代码耗时：【{}毫秒】", (System.currentTimeMillis() - startTimeThreadLocal.get()));
			String requestURL = request.getRequestURI();
			//log.info("当前请求的URL：【{}】", requestURL);

			if (modelAndView != null) {
				log.info("即将返回到MVC视图：{}", modelAndView.getViewName());

				if (modelAndView.getView() != null) {
					log.info("返回到MVC视图内容类型ContentType：{}", modelAndView.getView().getContentType());
				}

				if (!modelAndView.getModel().isEmpty()) {

					log.info("返回到MVC视图{}数据打印如下：", modelAndView.getViewName());
					_print("返回数据", (Map)transToMAP(modelAndView.getModel()));
				}
			}
		} catch (Exception e) {
			log.error("MVC 视图渲染-拦截器异常：", e);
		} finally {
			
		}

		log.info("--------- 一个MVC 视图渲染结束 ---------");
		
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		super.afterCompletion(request, response, handler, ex);
	}

	/**
	 * @Title whiteListCheck
	 * @Description 检查当前请求是否在免登录操作白名单中
	 * @param req
	 *            前端的请求
	 * @return true 是,无须登录即可放行,false 否,必须登录才可继续
	 */
	private boolean whiteListCheck(HttpServletRequest req) {
		String contextPath = req.getContextPath();
		String url = req.getRequestURI();
		if (url.equals(contextPath + "/index") || url.equals(contextPath + "/login")
				|| url.equals(contextPath + "/logins")
				|| url.startsWith(contextPath + "/wx")
				|| url.startsWith(contextPath+"/water")
				|| url.equals(contextPath + "/refresh") || url.startsWith(contextPath + "/static")
				|| url.equals(contextPath + "/getCacheData") || url.startsWith(contextPath + "/test")
			) {
			return true;
		}
		return false;
	}

	/**
	 * @Title hasLogin
	 * @Description 是否已登录
	 * @param req
	 * @return
	 */
	private boolean hasLogin(HttpServletRequest req) {
		HttpSession session = req.getSession(false);
		if (session == null) {
			return false;
		}
		Object sessionUser = session.getAttribute(Constants.SESSION_USER);
		if (sessionUser == null) {
			return false;
		}
		return true;
	}

	private void _print(String prefix, Map<String, ?> map) {
		if (map != null) {
			Set<String> keys = map.keySet();
			Iterator<String> iter = keys.iterator();
			while (iter.hasNext()) {

				String name = iter.next();
				if (name.contains("org.springframework.validation.BindingResult")) {
					continue;
				}

				String value = "";
				try {
					value = map.get(name).toString();
				} catch (Exception e) {
					log.error("转换参数【{}】发生异常：", name, e);
				}
				log.info("{} {}： {}", prefix, name, value);
			}
		}
	}

	private Map transToMAP(Map parameterMap) {
		// 返回值Map
		Map returnMap = new HashMap();
		Iterator entries = parameterMap.entrySet().iterator();
		Map.Entry entry;
		String name = "";
		String value = "";
		while (entries.hasNext()) {
			entry = (Map.Entry) entries.next();
			name = (String) entry.getKey();
			Object valueObj = entry.getValue();
			if (null == valueObj) {
				value = "";
			} else if (valueObj instanceof String[]) {
				String[] values = (String[]) valueObj;
				for (int i = 0; i < values.length; i++) {
					value = values[i] + ",";
				}
				value = value.substring(0, value.length() - 1);
			} else {
				value = valueObj.toString();
			}
			returnMap.put(name, value);
		}
		return returnMap;
	}

}
